/*
 * Copyright 2011 Katsunori Koyanagi
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package sweezy.swf.tools.abcdump
{
	import sweezy.swf.abc.structure.ClassTrait;
	import sweezy.swf.abc.structure.ScriptInfo;
	import sweezy.swf.abc.structure.TraitInfo;

	internal class ScriptDef extends ABCElementDef
	{

		private static var _internalScriptId:uint;

		private var _scriptId:uint;

		private var _scriptInfo:ScriptInfo;

		public function ScriptDef(container:ABCcontainerDef, scriptInfo:ScriptInfo)
		{
			super(container);

			_scriptId = _internalScriptId++;
			_scriptInfo = scriptInfo;
		}

		override public function dump(stream:IDumpStream):void
		{
			var publicClass:ClassDef;
			var publicVariable:VariableDef;
			var index:int;
			var classDef:ClassDef;
			var variableDef:VariableDef;
			var found:Boolean = false;

			for each (classDef in classDefs)
			{
				if (classDef.namespace === Utils.PUBLIC || classDef.namespace === Utils.INTERNAL)
				{
					publicClass = classDef;
					break;
				}
			}
			if (publicClass === null)
			{
				for each (variableDef in variableDefs)
				{
					if (variableDef.namespace === Utils.PUBLIC || variableDef.namespace === Utils.INTERNAL)
					{
						publicVariable = variableDef;
						break;
					}
				}
			}

			var packageName:String = publicClass !== null ? publicClass.name : publicVariable !== null ? publicVariable.name : "";
			var scriptName:String;
			
			index = packageName.indexOf("::");
			if (index > -1)
			{
				scriptName = packageName.substring(0, index).replace(/\./g, "/") + "/" + packageName.substring(index + 2);
				packageName = packageName.substring(0, index);
			}
			else
			{
				scriptName = packageName;
				packageName = "";
			}

			if (packageName !== "")
			{
				packageName = " " + packageName;
			}
			if(!scriptName){
				scriptName = "script" + _scriptId;
			}else{
				scriptName += ".as";
			}

			stream.printSection(scriptName);
			stream.println();
			stream.indentLevel++;
			stream.printSection("package");
			stream.println("package" + packageName);
			stream.println("{");
			stream.println();
			stream.indentLevel++;

			if (publicClass !== null)
			{
				stream.printSection("public class");
				publicClass.dump(stream);
			}
			else if (publicVariable !== null)
			{
				stream.printSection("public variable");
				publicVariable.dump(stream);
			}

			stream.indentLevel--;
			stream.println();
			stream.println("}");
			stream.println();

			stream.printSection("script initializer");
			new FunctionDef(_container, null, _scriptInfo, true).dump(stream);
			stream.println();

			found = false;
			for each (classDef in classDefs)
			{
				if (classDef.namespace === Utils.PUBLIC || classDef.namespace === Utils.INTERNAL)
				{
					continue;
				}
				if (!found)
				{
					found = true;
					stream.printSection("private classes");
				}

				classDef.dump(stream);
				stream.println();
			}

			found = false;
			for each (variableDef in variableDefs)
			{
				if (variableDef.namespace === Utils.PUBLIC || variableDef.namespace === Utils.INTERNAL)
				{
					continue;
				}
				if (!found)
				{
					found = true;
					stream.printSection("private variables");
				}

				variableDef.dump(stream);
				stream.println();
			}

			stream.indentLevel--;
		}

		private function get classDefs():Array
		{
			var classDefs:Array = [];

			for each (var trait:TraitInfo in _scriptInfo.traitInfos)
			{
				if (trait is ClassTrait)
				{
					var classTrait:ClassTrait = trait as ClassTrait;
					var classDef:ClassDef = new ClassDef(_container, classTrait);
					classDefs[classDefs.length] = classDef;
				}
			}

			return classDefs;
		}

		private function get variableDefs():Array
		{
			var variableDefs:Array = [];
			var traits:Array = _scriptInfo.traitInfos;

			for each (var trait:TraitInfo in traits)
			{
				if (Utils.isVariable(trait))
				{
					variableDefs[variableDefs.length] = new VariableDef(_container, trait, true);
				}
			}

			return variableDefs;
		}
	}
}
